package logger

import (
	"fmt"
	nested "github.com/antonfisher/nested-logrus-formatter"
	rotatelogs "github.com/lestrrat/go-file-rotatelogs"
	"github.com/pkg/errors"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"os"
	"path"
	"runtime"
	"strings"
	"time"
)

type Logging struct {
	File  string `properties:"file"`
	Level string `properties:"level,default=info"`
}

var Log = logrus.New()

func InitLogger(logging *Logging) {
	initLogPath(logging)
	baseLogPath := logging.File
	fmt.Printf("日志文件位置: %s\n", baseLogPath)
	writer, err := rotatelogs.New(
		baseLogPath+".%Y%m%d%H%M",
		rotatelogs.WithLinkName(baseLogPath),      // 生成软链，指向最新日志文件
		rotatelogs.WithMaxAge(7*24*time.Hour),     // 文件最大保存时间
		rotatelogs.WithRotationTime(24*time.Hour), // 日志切割时间间隔
	)
	if err != nil {
		Log.Errorf("config local file system logger2 error. %v\n", errors.WithStack(err))
	}
	formatter := &nested.Formatter{
		CallerFirst:     true,
		ShowFullLevel:   true,
		TimestampFormat: "2006-01-02 15:04:05.000",
		CustomCallerFormatter: func(f *runtime.Frame) string {
			s := strings.Split(f.Function, ".")
			funcName := s[len(s)-1]
			return fmt.Sprintf(" [%s#%s:%d]", path.Base(f.File), funcName, f.Line)
		},
	}
	Log.SetOutput(os.Stdout)
	level, err := logrus.ParseLevel(logging.Level)
	if err != nil {
		fmt.Printf("日志级别(%v)设置有误，更换为默认级别info\n", logging.Level)
	}
	Log.SetLevel(level)
	Log.SetReportCaller(true)
	Log.SetFormatter(formatter)
	lfHook := lfshook.NewHook(lfshook.WriterMap{
		logrus.DebugLevel: writer, // 为不同级别设置不同的输出目的
		logrus.InfoLevel:  writer,
		logrus.WarnLevel:  writer,
		logrus.ErrorLevel: writer,
		logrus.FatalLevel: writer,
		logrus.PanicLevel: writer,
	}, formatter)
	Log.AddHook(lfHook)
}

// initLogPath 初始化日志文件所在目录
func initLogPath(logging *Logging) {
	dir := path.Dir(logging.File)
	// 如果目录不存在，则创建目录
	if !exists(dir) {
		err := os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			fmt.Printf("日志文件所在目录创建失败\n")
			os.Exit(1)
		}
	}
}

func exists(path string) bool {
	//os.Stat获取文件信息
	_, err := os.Stat(path)
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}
